package com.spsoft.dmzeinvoice.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.spsoft.core.constants.CommonConstants;
import com.spsoft.core.model.leqidmz.param.LeqiHeader;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.dmzeinvoice.common.entity.KfptRes;
import com.spsoft.dmzeinvoice.model.vo.LeqiResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.zip.GZIPInputStream;

@Slf4j
@Component
@SuppressWarnings({"unchecked"})
public class SandboxRestTemplateUtil {

    @Resource
    private RestTemplate restTemplate;

    // 乐企安全密钥
    @Value("${leqi.securityKey}")
    private String securityKey;

    // 乐企沙箱测试标志
    @Value("${swagger.enabled:false}")
    private boolean sxcsbz;


    public String postLeQi(String jrdwptbh, String sydwptbh,String access_signature,String fwbm, String bodyJsonStr) {
        if(!sxcsbz){
            return "当前系统未配置沙箱环境，请联系管理员";
        }

        // 接收税局相应报文（未解密）
        String result;
        String url="https://lqpt.chinatax.gov.cn:8443/access/sandbox_kzfw/v1/"+fwbm;

        try {
            log.info("加密之前的请求入参:{}", bodyJsonStr);
            // 对请求报文加密
            String encbody = SM4Util.encryptEcb(securityKey, bodyJsonStr);

            HttpHeaders headers = new HttpHeaders();
            headers.add("jrdwptbh", jrdwptbh); // 添加接入单位平台编号
            headers.add("sydwptbh", sydwptbh); // 添加使用单位平台编号
            headers.add("access_signature", access_signature); // 添加使用单位平台编号

            GZIPInputStream gzip = null; // 商品服务编码返回时为gzip压缩格式
            BufferedReader reader = null;
            StringWriter writer = null;

            try {
                HttpEntity<String> entity = new HttpEntity<>(encbody, headers);
                log.info("调用乐企能力开放平台地址:{}", url);
                log.info("调用乐企能力开放平台请求头：{}，请求体：{}", JSONObject.toJSONString(headers), bodyJsonStr);
                // 向税局发送请求
                ResponseEntity<byte[]> responseEntity = restTemplate.postForEntity(url, entity, byte[].class);
                // 解析税局返回内容
                List<String> valuesAsList = responseEntity.getHeaders().getValuesAsList("content-encoding");
                // 如果返回 gzip 时处理
                if (!CollectionUtils.isEmpty(valuesAsList) && valuesAsList.contains("gzip")) {
                    gzip = new GZIPInputStream(new ByteArrayInputStream(responseEntity.getBody()));
                    reader = new BufferedReader(new InputStreamReader(gzip));
                    writer = new StringWriter();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        writer.write(line);
                    }
                    result = writer.toString();
                } else {
                    // 返回非 gzip 时处理
                    result = new String(responseEntity.getBody(), StandardCharsets.UTF_8);
                }
            } finally {
                if (Objects.nonNull(gzip)) {
                    IOUtils.closeQuietly(gzip);
                }
                if (Objects.nonNull(reader)) {
                    IOUtils.closeQuietly(reader);
                }
                if (Objects.nonNull(writer)) {
                    IOUtils.closeQuietly(writer);
                }
            }
            log.info("调用乐企能力开放平台响应报文：{}", result);

            KfptRes kfptRes = JSONObject.parseObject(result, KfptRes.class);

            /**
             * 如果返回不是 200 或有 error 节点则无需解密
             */
            if (!CommonConstants.HTTP_200.equals(kfptRes.getHttpStatusCode())) {
                return buildResult(kfptRes.getHttpStatusCode(), kfptRes.getBody().toString(), null);
            }
            LeqiResult<String> leqiResult = JSONObject.parseObject(kfptRes.getBody().toString(), LeqiResult.class);
            LeqiResult.ErrorInfo error = leqiResult.getResponse().getError();
            if (Objects.nonNull(error)) {
                return buildResult(error.getCode(), error.getMessage(), leqiResult.getResponse().getRequestId());
            }
            // 解密返回报文
            String data = leqiResult.getResponse().getData();
            String decdata = SM4Util.decryptEcb(securityKey, data);
            log.info("调用乐企能力开放平台响应报文解密：{}", decdata);
            leqiResult.getResponse().setData(decdata);

            // 成功处理
            result = JSONObject.toJSONString(leqiResult);
        } catch (ResourceAccessException e) {
            log.error("调用乐企能力开放平台出现网络异常", e);
            // 异常处理
            result = buildResult("9998", "调用乐企平台出现网络异常", null);
        } catch (Exception e) {
            log.error("调用乐企能力开放平台出现未知异常", e);
            // 异常处理
            result = buildResult("9999", e.getMessage(), null);
        }
        log.info("调用乐企能力开放平台响应报文转化后：{}", result);
        return result;
    }

    /**
     * 构造乐企返回数据
     * @param code 返回code
     * @param message 返回message
     */
    private String buildResult(String code, String message, String requestId) {
        LeqiResult<String> leqiResult = new LeqiResult<>();
        LeqiResult.ResponseInfo<String> responseInfo = new LeqiResult.ResponseInfo<>();
        LeqiResult.ErrorInfo errorInfo = new LeqiResult.ErrorInfo();
        errorInfo.setCode(code);
        errorInfo.setMessage(message);
        responseInfo.setError(errorInfo);
        if (StringUtils.isBlank(requestId)) {
            responseInfo.setRequestId(MDC.get("traceId"));
        } else {
            responseInfo.setRequestId(requestId);
        }
        leqiResult.setResponse(responseInfo);
        return JSONObject.toJSONString(leqiResult);
    }

}
